﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;

namespace editor.app
{
    /// <summary>
    /// SpaceLinkWindow.xaml 的交互逻辑
    /// </summary>
    public partial class SpaceLinkWindow : Window
    {
        Dictionary<string, MapView> _mapViewDic = new Dictionary<string, MapView>();
        int _w = 0, _h = 0;
        comm.objst.DStar.Data.Space[,] _spaces = null;

        public SpaceLinkWindow(int w, int h, comm.objst.DStar.Data.Space[,] spaces)
        {
            InitializeComponent();
            this.LoadConfig1();

            _w = w;
            _h = h;
            _spaces = spaces;

            for (int i = 0; i < w; i++)
            {
                gridLayer.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) });
            }
            for (int i = 0; i < h; i++)
            {
                gridLayer.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) });
            }

            Fill();

            gridLayer.Drag(MapViewDrag);

            KeyDown += new KeyEventHandler(SpaceLinkWindow_KeyDown);

            #region loop
            comm.ThreadHelper.Run(() =>
            {
                while (true)
                {
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        UpdateMask();
                    }));
                    Thread.Sleep(10);
                }
            });
            #endregion
        }

        void SpaceLinkWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (e.Key == Key.OemPlus)
                {
                    foreach (var item in _mapViewDic.Values)
                    {
                        item.PathSize += 2;
                    }
                }
                else if (e.Key == Key.OemMinus)
                {
                    foreach (var item in _mapViewDic.Values)
                    {
                        item.PathSize -= 2;
                    }
                }
                else if (e.Key == Key.D0)
                {
                    foreach (var item in _mapViewDic.Values)
                    {
                        item.PathSize = MapView.PATH_SIZE;
                    }
                }
                else if (e.Key == Key.Enter)
                {
                    gridLayer.Margin = new Thickness(4, 4, 0, 0);
                }
            }
        }

        Border _chooseBr = null;
        comm.lib.MapEvent _chooseEV = null;
        MapView.Obj _chooseObj = null;
        string _moveSpaceId = "";
        int _moveMapX = 0, _moveMapY = 0;
        MapView.Obj _enterObj = null;

        void Fill()
        {
            _mapViewDic.Clear();
            gridLayer.Children.Clear();

            for (int x = 0; x < _w; x++)
            {
                for (int y = 0; y < _h; y++)
                {
                    var space = _spaces[x, y];
                    if (space != null)
                    {
                        var mapData = App.DefineFile.GetMapData(space.MapId);
                        if (mapData == null)
                        {
                            #region not map
                            var br = new Border
                            {
                                Background = new SolidColorBrush(Color2.White(5)),
                                Padding = new Thickness(4)
                            };
                            br.Child = new TextBlock
                            {
                                Foreground = new SolidColorBrush(Color2.White(20)),
                                Text = space.SpaceId + " (" + space.MapId + ", map not found)"
                            };
                            br.SetValue(Grid.ColumnProperty, x);
                            br.SetValue(Grid.RowProperty, y);
                            gridLayer.Children.Add(br);
                            #endregion
                        }
                        else
                        {
                            #region has map
                            mapData.AddExObjDic(space.ObjDic);
                            mapData.FillAllObjPath(App.DefineFile);
                            var mapView = new MapView();
                            mapView.CmdCallback = ReceiveCmd;
                            mapView.Load(space.SpaceId, mapData, space.PathList);
                            mapView.SetValue(Grid.ColumnProperty, x);
                            mapView.SetValue(Grid.RowProperty, y);
                            gridLayer.Children.Add(mapView);
                            _mapViewDic.Add(space.SpaceId, mapView);
                            #endregion

                            #region contextMenu
                            var contextMenu = new ContextMenu { FontSize = 14 };
                            TextOptions.SetTextFormattingMode(contextMenu, TextFormattingMode.Display);

                            var mEditMap = new MenuItem { Header = "Edit Map" };
                            mEditMap.Click += new RoutedEventHandler((o, e) =>
                            {
                                var dmap = App.DefineFile.GetMap(space.MapId);
                                var window = new MapWindow(dmap.File, space.ObjDic, space.PathList);
                                window.OnSaveCallback = dic =>
                                {
                                    space.ObjDic.Clear();
                                    foreach (var objKey in dic.Keys)
                                    {
                                        space.ObjDic.Add(objKey, dic[objKey]);
                                    }
                                };
                                window.ShowDialog();
                                Fill();
                            });
                            contextMenu.Items.Add(mEditMap);

                            mapView.ContextMenu = contextMenu;
                            #endregion
                        }
                    }
                }
            }
        }
        void UpdateMask()
        {
            cvMask.Children.Clear();

            foreach (var view in _mapViewDic.Values)
            {
                foreach (var obj in view._objDic.Values)
                {
                    if (obj._sobj != null)
                    {
                        string m1Key, m2Key;
                        var m1 = obj._sobj.FindEV<comm.lib.MapEvent.MoveToSpace>(out m1Key);
                        var m2 = obj._sobj.FindEV<comm.lib.MapEvent.MoveToLocLabel>(out m2Key);
                        if (m1 != null && _mapViewDic.ContainsKey(m1.SpaceId))
                        {
                            #region m1
                            var view2 = _mapViewDic[m1.SpaceId];
                            var pt1 = obj._brDotDic[m1Key].TranslatePoint(new Point(), gridRoot);
                            var pt2 = view2.TranslatePoint(new Point(), gridRoot);
                            cvMask.Children.Add(new Line
                            {
                                X1 = pt1.X + 16,
                                Y1 = pt1.Y + 16,
                                X2 = pt2.X + view2.PathSize / 2 + m1.LocX * view2.PathSize,
                                Y2 = pt2.Y + view2.PathSize / 2 + m1.LocY * view2.PathSize,
                                Stroke = new SolidColorBrush(Color2.LightSkyBlue(50)),
                                StrokeThickness = 2
                            });
                            #endregion
                        }
                        else if (m2 != null && _mapViewDic.ContainsKey(m2.SpaceId))
                        {
                            #region m2
                            var view2 = _mapViewDic[m2.SpaceId];
                            if (view2._objDic.ContainsKey(m2.MapObjKey))
                            {
                                var obj2 = view2._objDic[m2.MapObjKey];
                                if (obj2._sobj != null)
                                {
                                    var cmd = obj2._sobj.FindEV<comm.lib.MapEvent.Command>();
                                    if (cmd != null && cmd.Type == comm.lib.MapEvent.CommandType.LOC_LABEL)
                                    {
                                        var pt1 = obj._brDotDic[m2Key].TranslatePoint(new Point(), gridRoot);
                                        var pt2 = obj2._ellDot.TranslatePoint(new Point(), gridRoot);
                                        #region path
                                        cvMask.Children.Add(new Line
                                        {
                                            X1 = pt1.X + 16,
                                            Y1 = pt1.Y + 16,
                                            X2 = pt2.X + view2.PathSize / 2,
                                            Y2 = pt2.Y + view2.PathSize / 2,
                                            Stroke = new SolidColorBrush(Color2.Red(50)),
                                            StrokeThickness = 2
                                        });
                                        #endregion
                                    }
                                }
                            }
                            #endregion
                        }
                    }
                }
            }

            if (_chooseBr != null && Mouse.LeftButton == MouseButtonState.Pressed)
            {
                var pt1 = _chooseBr.TranslatePoint(new Point(), gridRoot);
                var pt2 = Mouse.GetPosition(gridRoot);
                #region line
                cvMask.Children.Add(new Line
                {
                    X1 = pt1.X + 8,
                    Y1 = pt1.Y + 8,
                    X2 = pt2.X - 2,
                    Y2 = pt2.Y - 2,
                    Stroke = new SolidColorBrush(Color2.Red(80)),
                    StrokeThickness = 2
                });
                #endregion
            }
            else
            {
                #region choose
                if (_chooseEV != null)
                {
                    if (_chooseEV is comm.lib.MapEvent.MoveToSpace)
                    {
                        var ev = (comm.lib.MapEvent.MoveToSpace)_chooseEV;
                        ev.SpaceId = _moveSpaceId;
                        ev.LocX = _moveMapX;
                        ev.LocY = _moveMapY;
                    }
                    else if (_chooseEV is comm.lib.MapEvent.MoveToLocLabel)
                    {
                        var ev = (comm.lib.MapEvent.MoveToLocLabel)_chooseEV;
                        if (_enterObj._sobj != null)
                        {
                            var cmd = _enterObj._sobj.FindEV<comm.lib.MapEvent.Command>();
                            if (cmd != null && cmd.Type == comm.lib.MapEvent.CommandType.LOC_LABEL)
                            {
                                ev.SpaceId = _moveSpaceId;
                                ev.MapObjKey = _enterObj._objKey;
                            }
                        }
                    }
                    _chooseObj.Reload();
                }
                _chooseBr = null;
                _chooseEV = null;
                _chooseObj = null;
                #endregion
            }
        }
        void MapViewDrag(FrameworkElement sender, MouseEventArgs e, string type, double ox, double oy)
        {
            var pt = e.GetPosition(svLayer);
            double x = pt.X, y = pt.Y;
            x -= ox;
            y -= oy;
            gridLayer.Margin = new Thickness(x, y, 0, 0);
        }
        void ReceiveCmd(string cmd, MapView mapView, object[] args)
        {
            if (cmd == "evClick")
            {
                var obj = (MapView.Obj)args[0];
                var evKey = args[1].ToString();
                var br = (Border)args[2];

                _chooseObj = obj;
                _chooseEV = (comm.lib.MapEvent)obj._sobj.EVDic[evKey].Value;
                _chooseBr = br;
            }
            else if (cmd == "mapMove")
            {
                int x = (int)args[0], y = (int)args[1];
                _moveSpaceId = mapView._spaceId;
                _moveMapX = x;
                _moveMapY = y;
            }
            else if (cmd == "objEnter")
            {
                var obj = (MapView.Obj)args[0];
                _enterObj = obj;
            }
        }
    }
}
